﻿using System.Runtime.Serialization;
using System;
using System.Reflection;

namespace Honeycomb.Core
{
    /// <summary>
    /// Responsible for determining required assemblies that are not loaded before deserialization 
    /// can take place. 
    /// </summary>
    class AssemblyNameSerializationBinder : SerializationBinder
    {      
        /// <summary>
        /// AssemblyName of a required assembly that is not loaded. Null if all required assemblies
        /// are loaded.
        /// </summary>
        public string AssemblyName { get; private set; }

        /// <summary>
        /// Assembly manager for assembly lookups.
        /// </summary>
        private readonly AssemblyManager assemblyManager;

        /// <summary>
        /// Base type to return when serialization cannot take place, to prevent the binary 
        /// formatter to cause an exception.
        /// </summary>
        private readonly Type baseType;

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="assemblyManager">AssemblyManager instance.</param>
        /// <param name="baseType">Default type to resolve to.</param>
        public AssemblyNameSerializationBinder(AssemblyManager assemblyManager, Type baseType)
        {
            this.assemblyManager = assemblyManager;
            this.baseType = baseType;
        }

        /// <summary>
        /// BindToType override.
        /// </summary>
        /// <param name="assemblyName">Assembly name to look for.</param>
        /// <param name="typeName">Type name to look for.</param>
        /// <returns>Type of the requested assembly and type or base type if no requested type cannot be found.</returns>
        public override Type BindToType(string assemblyName, string typeName)
        {
            Assembly assembly = assemblyManager.GetAssemblyByName(assemblyName);
            if (assembly != null)
            {
                Type type = assembly.GetType(typeName);
                if (type != null)
                    return type;
            }

            AssemblyName = assemblyName;
            return baseType;
        }
    }
}
